import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_demo/ex/object.dart';
import 'package:flutter_demo/pages/page_with_title.dart';
import 'package:flutter_demo/widgets/app_widgets.dart';

class EditTextPage extends PageWithTitle {
  const EditTextPage({super.key}) : super("输入框(TextField)");

  @override
  List<Widget> buildContentWidgets(BuildContext context) {
    return const [
      PrimaryTitle("简介"),
      BodyText("输入框用于接收和显示用户输入的文本"),
      AppSpacer.large,
      LabelText("登录示例"),
      _TextFieldExample(),
      UlItem("TextField"),
      BodyText("输入框组件来实Material包，它基于Widget包的EditableText组件封装实现文本输"
          "入组件，支持Material主题样式，支持现代化的输入提示、前后图标等"),
      PrimaryHeaderLabelText(
        "controller",
        "文本编辑控制器，用于指定和获取输入框初始内容、选中字符，监听文本和选中字符变化",
      ),
      AppSpacer.normal,
      CategoryTitle("焦点处理"),
      PrimaryHeaderLabelText("autofocus", "自动取得焦点，一般是页面的第一输入组件设置"),
      PrimaryHeaderLabelText(
        "focusNode",
        "焦点节点，可以通过FocusScope.of(context).requestFocus来请求焦点转移到节点对应"
            "的组件上",
      ),
      PrimaryHeaderLabelText(
          "textInputAction",
          "软键盘上回车按钮的动作类型，比如next会将焦点转移到下个"
              "组件（先右后下），done则是显示一个完成按钮"),
      PrimaryHeaderLabelText(
          "onEditingComplete onSubmitted",
          "用户完成输入后（点击done、键盘回车等）的回调，有时候next动作查找下个输入框可能会失"
              "败，比如右侧有个可以点击的按钮，它会优先获取焦点，这种时候我们可以通过自定义回调"
              "来使焦点移动到目标输入框或者执行登录，它的默认实现是在提交内容到控制器后根据"
              "action的不同移动焦点或者自动失去焦点"),
      AppSpacer.normal,
      PrimaryHeaderLabelText(
        "decoration",
        "装饰器，它包含了除文本输入以外的其它样式和扩展部件",
      ),
      CategoryTitle("提示用户输入类型"),
      LabelText("一般输入类型是在输入框左侧或者上方显示，可以直接设置文本，样式由Material主题"
          "决定，也可以直接使用组件"),
      LabelText("    - icon 在输入框开始位置显示图标，它不包含在输入框的下划线内"),
      NoticeText("注意：Flutter对于这种图标排布都是将其底部对齐输入文本的基线，所以如果将"
          "Text作为icon设置进去会出现基线对齐问题，样式不满意可以参考示例自己用表格去布局"),
      LabelText("    - prefix 在输入框开始位置显示前缀"),
      LabelText("    - label 在输入框左上角显示的描述"),
      LabelText("    - hintText 在输入框没有内容时显示的提示语"),
      CategoryTitle("附加的操作按钮"),
      LabelText("    - suffix 在输入框结束位置显示末尾的组件，一般是用于显示一些清除按钮，"
          "密码可见按钮"),
      CategoryTitle("用户输入状态提醒"),
      LabelText("    - helper、error 在输入框左下角显示的帮助提示、异常提示，如输入不符合"
          "要求、有非法字符等"),
      LabelText("    - counter 在输入框右下角显示的当前输入长度，常用于评论之类场景，后台对"
          "存储长度有限制，这里可以根据用户输入的文本变化实时显示已输入多少字符或者还可以输入多"
          "少字符"),
      CategoryTitle("样式"),
      LabelText("    - filled 背景填充，配合fillColor设置背景色"),
      LabelText("    - border 边框，Flutter内部实现了下划线（默认）、外部边框等样式，可以"
          "通过disabledBorder、hoverColor、errorBorder、focusedBorder、"
          "focusedErrorBorder等属性来实现不同状态下显示不同样式的边框，其中hover是鼠标悬停"
          "时的样式，error则是设置error组件后使用的样式"),
      AppSpacer.normal,
      CategoryTitle("安全"),
      PrimaryHeaderLabelText(
        "obscureText",
        "掩盖文本，常用于密码输入，开启后用户不可复制文本",
      ),
      PrimaryHeaderLabelText("obscuringCharacter", "掩盖文本使用的字符"),
      PrimaryHeaderLabelText(
        "keyboardType",
        "输入键盘类型，使用TextInputType.visiblePassword可以向平台建议该输入框使用安全输"
            "入法，这在密码输入场景非常重要，安全输入法会自动屏幕系统截图、录像",
      ),
      AppSpacer.normal,
      CategoryTitle("字符过滤"),
      PrimaryHeaderLabelText(
          "inputFormatters", "输入格式化，可以同时指定多个实例，Flutter提供了两个实现："),
      LabelText("    - FilteringTextInputFormatter 按照字符类型过滤，用正则表达式来表示"
          "可用字符或不可用字符"),
      LabelText("    - LengthLimitingTextInputFormatter 限制字符长度，超出部分会被截"
          "取掉，但有时候后台的限制条件不是字符数量而是字节数量（数据库一般按照字节定义存储长度，"
          "而utf-8编码的字符像汉字会占用多个字节），这种情况就需要自己去实现字符过滤器，当然"
          "更为人性化的方式应该是显示当前输入长度，超出时提示用户而不是直接截取。"),
    ];
  }
}

class _TextFieldExample extends StatefulWidget {
  const _TextFieldExample();

  @override
  State<StatefulWidget> createState() {
    return _TextFieldExampleState();
  }
}

class _TextFieldExampleState extends State<StatefulWidget> {
  final _accountController = TextEditingController(text: "csw");
  final _accountFocusNode = FocusNode();
  var _showClearAccountInput = false;
  String? _accountErrorText;

  final _passwordController = TextEditingController(text: "123456");
  final _passwordFocusNode = FocusNode();
  var _showClearPasswordInput = false;
  var _passwordObscureText = true;
  String? _passwordErrorText;

  @override
  void initState() {
    super.initState();
    _accountController.addListener(() {
      setState(() {
        _showClearAccountInput = _accountController.text.isNotEmpty;
      });
    });
    _passwordController.addListener(() {
      final password = _passwordController.text;
      if (password.length < 8 || password.length > 32) {
        _onPasswordError(context, "密码长度应该在8~32个字符");
      }
      setState(() {
        _showClearPasswordInput = password.isNotEmpty;
      });
    });
  }

  @override
  void dispose() {
    _accountController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Table(
          columnWidths: const {
            0: FixedColumnWidth(60),
          },
          defaultVerticalAlignment: TableCellVerticalAlignment.baseline,
          textBaseline: TextBaseline.alphabetic,
          children: [
            TableRow(children: [
              Container(
                padding: const EdgeInsetsDirectional.symmetric(horizontal: 5),
                alignment: AlignmentDirectional.centerEnd,
                child: const Text("账号:"),
              ),
              TextField(
                controller: _accountController,
                focusNode: _accountFocusNode,
                textInputAction: TextInputAction.next,
                autofocus: true,
                inputFormatters: [
                  FilteringTextInputFormatter.allow(
                      RegExp(r"[0-9,a-z,A-Z,@,_,-]")),
                  LengthLimitingTextInputFormatter(32),
                ],
                onSubmitted: (text) {
                  FocusScope.of(context).requestFocus(_passwordFocusNode);
                },
                decoration: InputDecoration(
                  errorText: _accountErrorText,
                  suffix: _showClearAccountInput
                      ? InkWell(
                          onTap: () {
                            _accountController.clear();
                          },
                          child: Container(
                            padding: const EdgeInsetsDirectional.all(10),
                            child: Transform.rotate(
                              angle: pi / 4,
                              child: const Icon(
                                Icons.add_circle_outline,
                                size: 20,
                              ),
                            ),
                          ),
                        )
                      : null,
                ),
              ),
            ]),
            TableRow(children: [
              Container(
                padding: const EdgeInsetsDirectional.symmetric(horizontal: 5),
                alignment: AlignmentDirectional.centerEnd,
                child: const Text("密码:"),
              ),
              TextField(
                controller: _passwordController,
                focusNode: _passwordFocusNode,
                textInputAction: TextInputAction.done,
                obscureText: _passwordObscureText,
                obscuringCharacter: "*",
                // 明确指定为密码类型键盘（增强系统识别）
                keyboardType: TextInputType.visiblePassword,
                inputFormatters: [
                  FilteringTextInputFormatter.allow(RegExp(r"[0-9,a-z,A-Z]")),
                  LengthLimitingTextInputFormatter(32),
                ],
                onSubmitted: (text) {
                  _checkAndLogin();
                },
                decoration: InputDecoration(
                  errorText: _passwordErrorText,
                  suffix: Wrap(
                    children: <Widget>[].also((it) {
                      if (_showClearPasswordInput) {
                        it.add(InkWell(
                          onTap: () {
                            _passwordController.clear();
                          },
                          child: Container(
                            padding: const EdgeInsetsDirectional.all(10),
                            child: Transform.rotate(
                              angle: pi / 4,
                              child: const Icon(
                                Icons.add_circle_outline,
                                size: 20,
                              ),
                            ),
                          ),
                        ));
                      }
                      it.add(InkWell(
                        onTap: () {
                          setState(() {
                            _passwordObscureText = !_passwordObscureText;
                          });
                        },
                        child: Container(
                          padding: const EdgeInsetsDirectional.all(10),
                          child: Icon(
                            _passwordObscureText
                                ? Icons.visibility_off
                                : Icons.visibility,
                            size: 20,
                          ),
                        ),
                      ));
                    }),
                  ),
                ),
              ),
            ]),
          ],
        ),
        Center(
          child: FilledButton.tonal(
            onPressed: _checkAndLogin,
            child: const Text("登录"),
          ),
        ),
      ],
    );
  }

  void _onAccountError(BuildContext context, String hint) {
    FocusScope.of(context).requestFocus(_accountFocusNode);
    setState(() {
      _passwordErrorText = null;
      _accountErrorText = hint;
    });
  }

  void _onPasswordError(BuildContext context, String hint) {
    FocusScope.of(context).requestFocus(_passwordFocusNode);
    setState(() {
      _accountErrorText = null;
      _passwordErrorText = hint;
    });
  }

  void _checkAndLogin() {
    final account = _accountController.text;
    final password = _passwordController.text;
    if (account.isEmpty) {
      _onAccountError(context, "请输入账号");
    } else if (password.isEmpty) {
      _onPasswordError(context, "请输入密码");
    } else if (password.length < 8 || password.length > 32) {
      _onPasswordError(context, "密码长度应该在8~32个字符");
    } else {
      if (Random().nextBool()) {
        _onAccountError(context, "账号不存在");
      } else {
        _onPasswordError(context, "账号或密码错误");
      }
    }
  }
}
